﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Diagnostics;
using System.Collections.Generic;
using SQLVis.Vizualizador;
using System.Collections;
using generador;
using parser;
using SQLVis.Entidades;
using System.Windows.Input;
using System.Data.Linq;

namespace rgr
{
    class TestTreeMapNode : RGRTreeMapNode
    {
        public TestTreeMapNode( double theArea, String theName ) : 
            
            base( theName )

        {
            myArea = theArea;
        }

        public override double Size { get { return myArea; }}

        private double myArea;
    }

	public partial class TreeMapTestWindowClass
	{
        public string FileName = string.Empty;

        public TreeMapTestWindowClass()
		{
			this.InitializeComponent();

            
            txtVerdeDesde.Text = "2";

            txtAmarilloDesde.Text = "2";
            txtAmarilloHasta.Text = "4";

            txtNaranjaDesde.Text = "4";
            txtNaranjaHasta.Text = "7";

            txtRojoDesde.Text = "7";
           
            TheTreeMap.SendRenderPerfEvent = true;
		}

        private void Rectangle_MouseMove(object sender, MouseEventArgs e)
        {
            //solo mostrar el tooltip si se ha cargo el treemap
            if (TheTreeMap.Loaded)
            {
                //if (!floatingTip.IsOpen) { floatingTip.IsOpen = true; }

                Point currentPos = e.GetPosition(TheTreeMap);
                //get the data of the current position
                SQLVisTreeMapNode currentNode;
                if(TheTreeMap.ZoomRoot==null)
                    currentNode = TheTreeMap.FindNodeByPoint(currentPos);
                else
                    currentNode = (SQLVisTreeMapNode)TheTreeMap.ZoomRoot.FindNodeByPoint(currentPos);

                if (currentNode != null)
                {
                    if (TheTreeMap.CantidadConsultas > 1)
                    {
                        if (TheTreeMap.iZoom == 0)
                            MyTxtBx.Text = currentNode.PatternName;
                        else
                            MyTxtBx.Text = currentNode.ToString();


                        floatingTip.IsOpen = true;

                        floatingTip.HorizontalOffset = currentPos.X;
                        floatingTip.VerticalOffset = currentPos.Y + 240;
                    }
                    else
                        floatingTip.IsOpen = false;
                }
                else
                    floatingTip.IsOpen = false;
            }
        }

        private void Rectangle_MouseLeave(object sender, MouseEventArgs e)
        {
            //aca chequear que se haya ido del area del treemap
            floatingTip.IsOpen = false;
        }

        private void HandleTest1ButtonClick( object sender, RoutedEventArgs e )
        {

            //open file dialog
            // Create OpenFileDialog
            Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();

            // Set filter for file extension and default file extension
            dlg.DefaultExt = ".log";
            dlg.Filter = "MYSql Slow Query Logs (.log)|*.log";

            // Display OpenFileDialog by calling ShowDialog method
            Nullable<bool> result = dlg.ShowDialog();

            // Get the selected file name and display in a TextBox
            if (result == true)
            {
                // Open document
                FileName = dlg.FileName;
                TheTreeMap.TreeMapData = LoadSlowQueryLog(FileName);
                //load numbers of queries and avg time
                TheTreeMap.CantidadConsultas = TheTreeMap.TreeMapData.TotalChildSize;
                TheTreeMap.TiempoPromedio = TheTreeMap.CalcularTiempoPromedio();
                //focus on the control
                TheTreeMap.Focus();
            }
            //TheTreeMap.TreeMapData = LoadSlowQueryLog("../../../logslowquerysgenerado.log");

        }

        private void Handle_FilterButtonClick(object sender, RoutedEventArgs e)
        {
            //TODO: Mostrar waiting screen

            if (FileName != string.Empty)
            {
                //obtener los criterios definidos
                IDictionary<string, object> filters = new Dictionary<string, object>();
                //TODO:Agregar funcion para validar los valores ingresados!!

                if (txtCantidadConsultasDesde.Text.Trim() != string.Empty && txtCantidadConsultasHasta.Text.Trim() != string.Empty)
                {
                    KeyValuePair<int,int> cantcon = new KeyValuePair<int, int>(Convert.ToInt32(txtCantidadConsultasDesde.Text), Convert.ToInt32(txtCantidadConsultasHasta.Text));
                    filters.Add("#", cantcon);
                }

                 if (txtRowsEnviadosDesde.Text.Trim() != string.Empty && txtRowsEnviadosHasta.Text.Trim() != string.Empty)
                {
                     KeyValuePair<int,int> rowsEnv = new KeyValuePair<int, int>(Convert.ToInt32(txtRowsEnviadosDesde.Text), Convert.ToInt32(txtRowsEnviadosHasta.Text));
                     filters.Add("#RowsEnviados", rowsEnv);
                }

                 if (txtRowScanneadosDesde.Text.Trim() != string.Empty && txtRowScanneadosHasta.Text.Trim() != string.Empty)
                 {
                     KeyValuePair<int, int> rowsEnv = new KeyValuePair<int, int>(Convert.ToInt32(txtRowScanneadosDesde.Text), Convert.ToInt32(txtRowScanneadosHasta.Text));
                     filters.Add("#RowsScanneados", rowsEnv);
                 }

                 if (txtTiempoPromedioDesde.Text.Trim() != string.Empty && txtTiempoPromedioHasta.Text.Trim() != string.Empty)
                 {
                     KeyValuePair<double, double> rangoTiempos = new KeyValuePair<double, double>(Convert.ToDouble(txtTiempoPromedioDesde.Text), Convert.ToDouble(txtTiempoPromedioHasta.Text));
                     filters.Add("RangoTiempos", rangoTiempos);
                 }

                TheTreeMap.TreeMapData = LoadSlowQueryLog(FileName, filters);
                //load numbers of queries and avg time
                TheTreeMap.CantidadConsultas = TheTreeMap.TreeMapData.TotalChildSize;
                TheTreeMap.TiempoPromedio = TheTreeMap.CalcularTiempoPromedio();
            }

        }
        

        //TestTreeMapNode root;
        
        private int DoIntParse( string s, int defaultValue )
        {
            try {
                return int.Parse( s );
            } catch( Exception ) {
                return defaultValue;
            }
        }

        //public void HandleHandledKeyDown(object sender, RoutedEventArgs e)
        //{
        //    KeyEventArgs ke = e as KeyEventArgs;
        //    if (ke.Key == Key.Space)
        //    {
        //        ke.Handled = false;
        //    }
        //}

        public Brush GetColor(double time)
        {
            BrushConverter conv = new BrushConverter();

            //dependiendo del tiempo, el color va ser diferente
            if (time <= Convert.ToDouble(txtVerdeDesde.Text.Trim()))
                return (Brush)conv.ConvertFromString("#ffffb2");
            else if (Between(time, Convert.ToDouble(txtAmarilloDesde.Text.Trim()), Convert.ToDouble(txtAmarilloHasta.Text.Trim())))
                return (Brush)conv.ConvertFromString("#fecc5c");
            else if (Between(time, Convert.ToDouble(txtNaranjaDesde.Text.Trim()), Convert.ToDouble(txtNaranjaHasta.Text.Trim())))
                return (Brush)conv.ConvertFromString("#fd8d3c");
            else if (time >= Convert.ToDouble(txtRojoDesde.Text.Trim()))
                return (Brush)conv.ConvertFromString("#e31a1c");
            else
                return Brushes.Black;
            

        
        }

        public static bool Between(double num, double lower, double upper)
        {
            return lower <= num && num <= upper;
        }

        //TODO: hacer un wrapper y luego cargar de disco el archivo que genera facundo
        public SQLVisTreeMapNode LoadSlowQueryLog(string path)
        {
            SQLVisTreeMapNode root = new SQLVisTreeMapNode(new SQLPattern(),0);
            IList<SQLPattern> res = Program.Parse(path);
            SQLVisTreeMapNode[] rootChildren = new SQLVisTreeMapNode[res.Count];
            int i = 0;
            foreach (var pattern in res)
            {
                SQLVisTreeMapNode nodo = new SQLVisTreeMapNode( pattern , GetColor( pattern.AverageTime),1 );
                //calcular los hijos recursivamente
                LoadChildren(ref nodo, pattern);
                //AddRandomChildren(ref nodo, 23, 8);
                //asignar el nodo
                rootChildren[i] = nodo;
                i++;

            }

            root.AddChildren(rootChildren);
           

            return root;
        }

        public SQLVisTreeMapNode LoadSlowQueryLog(string path , IDictionary<string,object> filters)
        {
            SQLVisTreeMapNode root = new SQLVisTreeMapNode(new SQLPattern(), 0);
            IList<SQLPattern> res = Program.Parse(path);
            //filter the patterns based on the defined criteria
            IList<SQLPattern> FilteredResult = FilterQueries(res, filters);

            SQLVisTreeMapNode[] rootChildren = new SQLVisTreeMapNode[FilteredResult.Count];
            int i = 0;
            foreach (var pattern in FilteredResult)
            {
                SQLVisTreeMapNode nodo = new SQLVisTreeMapNode(pattern, GetColor(pattern.AverageTime), 1);
                //calcular los hijos recursivamente
                LoadChildren(ref nodo, pattern);
                //asignar el nodo
                rootChildren[i] = nodo;
                i++;

            }

            root.AddChildren(rootChildren);


            return root;
        }

        private IList<SQLPattern> FilterQueries(IList<SQLPattern> res, IDictionary<string, object> filters)
        {

            IList<SQLPattern> resultList = new List<SQLPattern>();
            foreach (SQLPattern pattern in res)
            {
                bool addToResult = true;
               

                if (filters.ContainsKey("#RowsEnviados"))
                {
                    KeyValuePair<int, int> RowsEnviados = (KeyValuePair<int, int>)filters["#RowsEnviados"];
                    //recorrer los queries y filtrar
                    pattern.SlowQueries = ((List<InfoDeLaQuery>)pattern.SlowQueries).FindAll(delegate(InfoDeLaQuery q)
                                                           {
                                                               return q.RowsSent >= RowsEnviados.Key && q.RowsSent <= RowsEnviados.Value;
                                                           }
                                                           );

                   if(pattern.SlowQueries.Count==0)
                       addToResult = false;
                }

                if (filters.ContainsKey("#RowsScanneados"))
                {
                    KeyValuePair<int, int> RowsScanneados = (KeyValuePair<int, int>)filters["#RowsScanneados"];
                    //recorrer los queries y filtrar
                    pattern.SlowQueries = ((List<InfoDeLaQuery>)pattern.SlowQueries).FindAll(delegate(InfoDeLaQuery q)
                    {
                        return q.RowsExamined >= RowsScanneados.Key && q.RowsExamined <= RowsScanneados.Value;
                    }
                                                           );

                    if (pattern.SlowQueries.Count == 0)
                        addToResult = false;

                }

                if (filters.ContainsKey("RangoTiempos"))
                {
                    KeyValuePair<double, double> RangoTiempos = (KeyValuePair<double, double>)filters["RangoTiempos"];
                    //recorrer los queries y filtrar
                    pattern.SlowQueries = ((List<InfoDeLaQuery>)pattern.SlowQueries).FindAll(delegate(InfoDeLaQuery q)
                    {
                        return q.QueryTime >= RangoTiempos.Key && q.QueryTime <= RangoTiempos.Value;
                    }
                                                           );

                    if (pattern.SlowQueries.Count == 0)
                        addToResult = false;
                }

                //filtrar por Cantidad consultas
                if (filters.ContainsKey("#"))
                {
                    KeyValuePair<int, int> CantidadConsultas = (KeyValuePair<int, int>)filters["#"];
                    if (pattern.Count() >= CantidadConsultas.Key && pattern.Count() <= CantidadConsultas.Value)
                    {
                        addToResult = true;
                    }
                    else
                        addToResult = false;

                }


                //si paso los filtros lo agregamos
                if (addToResult)
                    resultList.Add(pattern);
               

            }

            return resultList;
        }


        private void LoadChildren(ref SQLVisTreeMapNode nodo, SQLPattern pattern)
        {

            IList<InfoDeLaQuery> subPatterns = pattern.SlowQueries;
            SQLVisTreeMapNode[] rootChildren = new SQLVisTreeMapNode[subPatterns.Count];
            int i = 0;
            foreach (InfoDeLaQuery sp in subPatterns)
            {
                SQLPattern subPattern = new SQLPattern(sp);
                SQLVisTreeMapNode nodoHijo = new SQLVisTreeMapNode(subPattern, GetColor(subPattern.AverageTime),2);

                rootChildren[i] = nodoHijo;
                i++;
            }

            nodo.AddChildren(rootChildren);
            
        }

        

        private const String RenderTimesDesc        = "       Render Times";
        private const String LayoutComputeTimesDesc = "Layout Computations";

        void DumpStatsHader( String prefix )
        {
            for( int i = 0; i < prefix.Length; i++ ) {
                Console.Write( ' ' );
            }

            Console.WriteLine( "| Count      Min       LQ    Median     Mean       UQ      Max     %iqrange   %Range" );
        }

        void DumpStats( List<double> data, String desc )
        {
            double min;
            double lq;
            double median;
            double mean;
            double uq;
            double max;
            double iqrange;
            double prange;

            if ( !ComputeStats( data, out min, out lq, out median, out mean, out uq, out max, out iqrange, out prange ) ) {
                Console.WriteLine( "{0}| -no data-", desc );
                return;
            }

               //                  | Count      Min       LQ    Median     Mean       UQ      Max     %iqrange   %Range
               // Render      Times|   100      6.1      6.4       6.7      7.5      8.0     24.6        23.4%   277.0%

            Console.WriteLine( "{0}|  {1,4}   {2,6:N1}   {3,6:N1}    {4,6:N1}   {5,6:N1}   {6,6:N1}   {7,6:N1}      {8,6:N1}%  {9,6:N1}%",
                              desc,            // 0
                              data.Count,      // 1
                              min,             // 2
                              lq,              // 3
                              median,          // 4
                              mean,            // 5
                              uq,              // 6
                              max,             // 7
                              iqrange,         // 8
                              prange           // 9
                              );
        }

        bool ComputeStats( List<double> data, 
                           out double min,
                           out double lq,
                           out double median, 
                           out double mean, 
                           out double uq, 
                           out double max,
                           out double iqrange,
                           out double prange
                         )
        {
            if ( data.Count == 0 ) {
                min = 0.0;
                lq = 0.0;
                mean = 0.0;
                median = 0.0;
                uq = 0.0;
                max = 0.0;
                iqrange = 0.0;
                prange = 0.0;
                return false;
            }

            data.Sort();
            double sum = 0.0;
            double tmin = double.MaxValue;
            double tmax = double.MinValue;

            for ( int i = 0; i < data.Count; i++ ) {
                sum += data[i];
                tmin = Math.Min( tmin, data[i] );
                tmax = Math.Max( tmax, data[i] );
            }

            mean = sum / data.Count;
            min = tmin;
            max = tmax;

            // calcuate the median
            if ( data.Count == 1 ) {
                // one is a special case
                median = data[0];
            } else
            if ( data.Count == 2 ) {
                // two is a special case
                median = ( data[0] + data[1] )/2;
            } else
            if ( ( data.Count & 1 ) != 0 ) {
                // number of sortedSamples is odd - just use the middle value.
                median = data[( data.Count+1 )/2];
            } else {
                // number of sortedSamples is even
                median = ( data[data.Count/2] + data[( data.Count/2 )+1] ) / 2;
            }

            lq = data[  data.Count / 4     ];
            uq = data[ (data.Count / 4) * 3];

            iqrange = ( ( uq  -  lq ) / median ) * 100.0;
            prange  = ( ( max - min ) / median ) * 100.0;

            return true;
        }

        //private void SetAreaLimitFromTB()
        //{
        //    try {
        //        double newv = double.Parse( AreaLimitTextBox.Text );
        //        if ( newv < 0.0 || newv > 1000000000.0 ) {
        //            System.Windows.MessageBox.Show( "Validation Error",
        //                                            "Please enter a numeric value >= 0.0 and < 100,000,000" );

        //        } else {
        //            if ( newv < ( 1.0 - double.Epsilon ) ) {
        //                TheTreeMap.AreaLimit = 0.0;
        //            } else {
        //                TheTreeMap.AreaLimit = newv;
        //            }
        //        }
        //    } catch ( FormatException ) {
        //        System.Windows.MessageBox.Show( "Please enter a number - other text is invalid",
        //                                        "Validation Error" );
        //    } catch ( OverflowException ) {
        //        System.Windows.MessageBox.Show( "That number is WAY TOO BIG!",
        //                                        "Validation Error" );
        //    } catch( Exception ) {
        //        System.Windows.MessageBox.Show( "Something really weird happened",
        //                                        "Validation Error" );
        //    }

        //    AreaLimitTextBox.Text = String.Format( "{0:N2}", TheTreeMap.AreaLimit );
        //}

        //private void AreaLimitTBKeyUp( object sender, System.Windows.Input.KeyEventArgs e )
        //{
        //    if ( e.Key == System.Windows.Input.Key.Enter ) {
        //        SetAreaLimitFromTB();
        //    }
        //}

        //private void AreaLimitTBLostKBFocus( object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e )
        //{
        //    SetAreaLimitFromTB();
        //}

        //private void SetInseLengthFromTB()
        //{
        //    try {
        //        double newv = double.Parse( InsetLengthTextBox.Text );

        //        if ( newv < 0.0 || newv > 1000000000.0 ) {
        //            System.Windows.MessageBox.Show( "Please enter a numeric value >= 0.0 and < 100,000,000",
        //                                            "Validation Error" );

        //        } else {
        //            if ( newv < ( 1.0 - double.Epsilon ) ) {
        //                TheTreeMap.InsetLength = 0.0;
        //            } else {
        //                TheTreeMap.InsetLength = newv;
        //            }
        //        }
        //    } catch ( FormatException ) {
        //        System.Windows.MessageBox.Show( "Please enter a number - other text is invalid",
        //                                        "Validation Error" );
        //    } catch ( OverflowException ) {
        //        System.Windows.MessageBox.Show( "That number is WAY TOO BIG!",
        //                                        "Validation Error" );
        //    } catch ( Exception ) {
        //        System.Windows.MessageBox.Show( "Something really weird happened",
        //                                        "Validation Error" );
        //    }

        //    InsetLengthTextBox.Text = String.Format( "{0:N2}", TheTreeMap.InsetLength );
        //}

        //private void InsetLengthTBKeyUp( object sender, System.Windows.Input.KeyEventArgs e )
        //{
        //    if ( e.Key == System.Windows.Input.Key.Enter ) {
        //        SetInseLengthFromTB();
        //    }
        //}

        //private void InsetLengthTBLostKBFocus( object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e )
        //{
        //    SetInseLengthFromTB();
        //}


        private enum CalcTypes { CalcRenderTimes, CalcResizeTimes };
        CalcTypes CalcType = CalcTypes.CalcRenderTimes;

        private int changeSteps;
        public delegate void AnimiateSizeDelegate();
        public AnimiateSizeDelegate AnimiateSizeSignal;

        private const int PerfListSize = 100;

        private List<double> RenderTimes;
        private List<double> RenderSizeTimes;

       

        Random rnd = new Random( 1234 );

        private int NumRootChildren =  5;
        private int MinChildren     =  5;
        private int MaxChildren     = 15;
        private int MinDepth        =  3;
        private int MaxDepth        =  7;
        private int NodeMaxDepth;

        private int TotalNodes;
    }
}